#include <iostream>
#include <string>
#include <cstring>
#include <ctime>
#include <cstdlib>
#include "Socket.hpp"
#include "protocol.hpp"
using namespace std;

int main(int argc, char* args[]) {
    if (argc != 3) {
        cout << "Usage:\n" << args[0] << "server_ip server_port\n" << endl;
        return 0; 
    }
    string serverip = args[1];
    uint16_t serverport = stoi(args[2]);
    net_work::Socket* s = new net_work::TcpSocket();
    // 创建一个链接套接字
    if (!s->BuildConnectSocketMethod(serverip, serverport)) {
        cerr << "connect " << serverip << ": " << serverport << ", failed!" << endl;
    } else {
        cout << "connect " << serverip << ": " << serverport << ", success!" << endl; 
    }
    unique_ptr<Protocol::Factory> fact = unique_ptr<Protocol::Factory>();

    // 先种一颗随机数种子
    srand(time(nullptr) ^ getpid() ^ pthread_self());
    const string opers = "+-*/%&^";
    while (true) {
        int x = rand() % 100;
        usleep(rand() % 888);
        int y = rand() % 100;
        usleep(rand() % 777);
        char op = opers[rand() % opers.size()];
        shared_ptr<Protocol::Request> req = fact->BuildRequest(x, y, op);
        // 序列化
        string requeststr;
        req->Serialize(&requeststr);
        // cout << "requeststr == " << requeststr << endl;
        // 添加报头
        requeststr = Protocol::Encode(requeststr);
        // cout << "requeststr == " << requeststr << endl;

        // 发送
        s->Send(requeststr);
        // cout << "Send??" << endl; 
        string responsestr;
        while (true) {
            // 读取响应
            if (!s->Recv(&responsestr, 1024)) {
                break;
            }
            // cout << "Recv??" << endl;
            // 对报文进行解析
            string response;
            if (!Protocol::Decode(responsestr, &response)) {
                continue;
            }
            auto resp = fact->BuildResponse();
            // 对response进行反序列化
            resp->DeSerialize(response);

            // 得到了计算结果
            printf("[%d %c %d]== %d (%d)\n", req->GetX(), req->GetOp(), req->GetY(), resp->GetResult(), resp->GetCode());
            break;
        }

        sleep(1);
    }

    s->CloseSockFd();

    return 0;
}